package at.pimpmypipe.filter;

import java.io.StreamCorruptedException;
import java.security.InvalidParameterException;

import at.pimpmypipe.interfaces.Readable;
import at.pimpmypipe.interfaces.Writeable;

public abstract class AbstractSource<out> implements Readable<out>, Runnable {

	private Writeable<out> _output = null;

	public static Object ENDING_SIGNAL = null;
	
	public AbstractSource() {
		
	}

	public AbstractSource(Writeable<out> output) throws InvalidParameterException {
		if (output == null) {
			throw new InvalidParameterException("output can't be null!");
		}
		_output = output;
	}

	protected void writeOutput(out value) throws StreamCorruptedException {
		if (_output != null) {
			if (value == ENDING_SIGNAL) {
				beforeSendingEndingSignal();
			}
			_output.write(value);
		} else {
			throw new StreamCorruptedException("output is null");
		}
	}

	/**
	 * send a signal, that the end of the stream has been reached
	 */
	protected void sendEndSignal() throws StreamCorruptedException {
		writeOutput(null);
	}

	/**
	 * derived class may override this, if they are interested in getting
	 * informed before the ending-signal is sended
	 */
	protected void beforeSendingEndingSignal() throws StreamCorruptedException {
	}
	
	/**
	 * runs the filter in active-mode
	 */
	public void run() {
		out output = null;
		try {
			do {
				output = read();

				if (output != null) {
					writeOutput(output);
				}
			} while (output != null);
			sendEndSignal();
		} catch (StreamCorruptedException e) {
			System.out.print("Thread reports error: ");
			System.out.println(Thread.currentThread().getId() + " ("
					+ Thread.currentThread().getName() + ")");
			e.printStackTrace();
		}
	}

	public void setOutput(Writeable<out> output) {
		_output = output;
	}
}
